#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Copyright © 启明星辰 版权所有
# @Time    : 2024/6/4 10:43
# @Author  : 胡浩浩
# @File    : engine.py
# @IDE     : PyCharm
# @description :
import copy
import json
import random
import re
from typing import Union
import requests
import jmespath

from login.bitsun_login import BitSunLogin

from models.case_model import CaseSuiteBase, CaseSuiteLogs, CaseStepBase, CheckerBase, CaseStepLogs
from tools.params_replace import ParamsReplace

variables = {
    "origin": "",
    "product": "csa"
}
function_list = [
    [
        "int_to_str",
        """def int_to_str(num: int) -> str:
    return str(num)
        """,
        100
    ]
]
test_result = []


def get_str(str_params) -> str:
    return random.choice(str_params)


def get_random_int(min_num, max_num) -> int:
    return random.randint(min_num, max_num)


class TestEngine:
    def __init__(self, case: CaseSuiteBase, session: requests.Session, env_host):
        self.test_case = case
        self.session = session
        self.host = env_host
        self.variables = {
            "host": self.host,
            "origin": "",
            "product": "csa"
        }
        self.case_run_logs = CaseSuiteLogs(**{
            "suite_name": self.__replace(self.test_case.suite_name),
            "suite_desc": self.__replace(self.test_case.suite_desc),
            "variables": [],
            "test_steps": []

        })

        print("我是初始化方法，已执行完成")

    def __replace(self, source_params):
        def replace_variable(match):
            var_name = match.group(1)
            if var_name in self.variables:
                return str(self.variables[var_name])
            else:
                if "(" in var_name and ")" in var_name:
                    try:
                        return str(eval(var_name))
                    except Exception as e:
                        raise Exception('表达式{}无法计算: {}'.format(var_name, str(e)))
                else:
                    raise Exception('变量{}不存在'.format(var_name))

        pattern = r"\${([^{}]*)}"
        while True:
            source_params, num_replacements = re.subn(pattern, replace_variable, source_params)
            if num_replacements == 0:
                break

        return source_params

    def __dict_replace(self, params: Union[dict, list]):
        if isinstance(params, dict):
            for key, value in params.items():
                if isinstance(value, dict):
                    self.__dict_replace(value)
                elif isinstance(value, list):
                    for item in value:
                        if isinstance(item, dict):
                            self.__dict_replace(item)
                else:
                    params[key] = self.__replace(value)
        return params

    def __set_variables(self):
        if self.test_case.variables:
            for key, value in self.test_case.variables.items():
                self.variables[key] = self.__replace(value)
                self.case_run_logs.variables.append(f"局部变量{key}的值{self.variables[key]}保存成功")

        print("我是__set_variables方法，已执行完成")
        print(self.variables)

    def __setup(self, current_case: CaseStepBase, current_step: CaseStepLogs):
        """
            setup函数中可以执行一些前置操作，比如说设置变量，执行函数
        :return:
        """
        if current_case.set_up:
            for function in current_case.set_up:
                result = re.match(r'\$\{(.*?)->\((.*?)\)}', function)
                if result:
                    self.variables[result.group(2)] = eval(result.group(1))
                    current_step.set_up.append(
                        f"函数{result.group(1)}的值{self.variables[result.group(2)]}已保存为局部变量{result.group(2)}")

        print("我是__setup方法，已执行完成")

    def __teardown(self, current_case: CaseStepBase, current_step: CaseStepLogs):
        if current_case.tear_down:
            for function in current_case.tear_down:
                result = re.match(r'\$\{(.*?)->\((.*?)\)}', function)
                if result:
                    self.variables[result.group(2)] = eval(result.group(1))
                    current_step.tear_down.append(
                        f"函数{result.group(1)}的值{self.variables[result.group(2)]}已保存为局部变量{result.group(2)}")
        print("我是__teardown方法，已执行完成")

    def __send_request(self, current_case: CaseStepBase, current_step: CaseStepLogs) -> requests.Response:
        if current_case.request:
            method = current_step.request.method = current_case.request.method
            path = current_step.request.path = current_case.request.path
            headers = current_step.request.headers = self.__dict_replace(current_case.request.headers)
            params = current_step.request.params = current_case.request.params
            data = current_step.request.data = current_case.request.data
            response = self.session.request(method=method, url=self.host + path, headers=headers, params=params,
                                            data=data)
            print(response.text)
            current_step.response = response.text
            return response
        print("我是__send_request法，已执行完成")

    def __data_extract(self, response: requests.Response, extract: Union[None, dict],
                       current_step: CaseStepLogs) -> None:
        if extract and response.headers.get("Content-Type") and "application/json" in response.headers.get(
                "Content-Type"):
            for key, value in extract.items():
                self.variables[key] = jmespath.search(value, response.json())
                current_step.extract.append(
                    f"接口响应中{value}的值{self.variables[key]}已保存为局部变量{key}")
        else:
            pass
        print("我是__data_extract法，已执行完成")
        print(variables)

    def __checker(self, response: requests.Response, checker: CheckerBase, current_step: CaseStepLogs) -> None:
        checker_result_flag = True
        if checker and response.headers.get("Content-Type") and "application/json" in response.headers.get(
                "Content-Type"):
            if checker.code != response.status_code:
                checker_result_flag = False
                current_step.checker.code = f"code断言失败,期望值{checker.code},实际值{response.status_code}"
            else:
                current_step.checker.code = response.status_code
            if checker.json:
                for express in checker.json:
                    if not jmespath.search(express, response.json()):
                        checker_result_flag = False
                        actual_value = jmespath.search(express.split("==")[0], response.json())
                        current_step.checker.json.append(
                            f"{express}断言失败,实际值为{actual_value},类型为{type(actual_value).__name__}")
            if checker.re:
                for express in checker.re:
                    if not re.search(express, response.text):
                        checker_result_flag = False
                        current_step.checker.re.append(f"正则表达式{express}断言失败,匹配结果为False")
            if checker.contains:
                for sub_str in checker.contains:
                    if not sub_str in response.text:
                        checker_result_flag = False
                        current_step.checker.contains.append(f"字符串{sub_str}不在响应中")
                    else:
                        current_step.checker.contains.append(f"字符串{sub_str}在响应中")
        if checker_result_flag:
            print("断言成功")
            current_step.checker.check_result = "断言成功"
        else:
            print("断言失败")
            current_step.checker.check_result = "断言失败"

        print("我是__assert法，已执行完成")

    def run(self):
        self.__set_variables()
        for item in self.test_case.test_steps:
            step_logs = CaseStepLogs(
                **{
                    "step_name": "",
                    "step_desc": "",
                    "wait_time": 0,
                    "set_up": [],
                    "tear_down": [],
                    "request": {
                        "path": "",
                        "method": "",
                        "headers": {},
                        "data": {},
                        "params": {},
                        "files": {}
                    },
                    "response": {},
                    "sql_data": [],
                    "downloads": [],
                    "extract": [],
                    "checker": {
                        "check_result": "",
                        "code": None,
                        "json": [],
                        "re": [],
                        "contains": []
                    }
                }
            )
            step_logs.step_name = self.__replace(item.step_name)
            step_logs.step_desc = self.__replace(item.step_desc)
            self.__setup(item, step_logs)
            response = self.__send_request(item, step_logs)
            self.__data_extract(response, item.extract, step_logs)
            self.__checker(response, item.checker, step_logs)
            self.__teardown(item, step_logs)
            self.case_run_logs.test_steps.append(step_logs)

        return self.case_run_logs.json()


def start(current_session: requests.Session, host: str, case_suite_list: list):
    all_case_run_logs = []
    for test_case in case_suite_list:
        case_suite = CaseSuiteBase(**test_case)
        test_result = TestEngine(case_suite, current_session, host).run()
        all_case_run_logs.append(json.loads(test_result))
    print(all_case_run_logs)
    print(json.dumps(all_case_run_logs,ensure_ascii=False))


if __name__ == '__main__':
    test_case = {
        "suite_name": "场景名称_不改的人是${product}",
        "suite_desc": "场景描述信息_不改的人是pig${get_str('${product}')}",
        "variables": {
            "username": "huhaohao",
            "password": "123456",
            "code": "${get_random_int(100,200)}",
            "code1": "220${get_random_int(100,200)}_shre"
        },
        "test_steps": [
            {
                "step_name": "_basic_taskInstance_mytaskPagerV2${product}",
                "step_desc": "${get_str('${product}')}",
                "wait_time": 0,
                "set_up": [
                    "${get_str('2dcsxd')->(my_name)}"
                ],
                "tear_down": [
                    "${get_str('erwewfds')->(password1)}"
                ],
                "request": {
                    "path": "/basic/taskInstance/mytaskPagerV2",
                    "method": "get",
                    "headers": {
                        "Accept": "*/*",
                        "Accept-Language": "zh-CN,zh;q=0.9",
                        "Cache-Control": "no-cache",
                        "Connection": "keep-alive",
                        "Pragma": "no-cache",
                        "Referer": "${host}$/main-project-front/",
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
                    },
                    "params": {
                        "currentPage": "1",
                        "pageSize": "5",
                        "qp-status-in": "0,1,2"
                    },
                    "data": None,
                    "files": {
                        "file": None
                    }
                },
                "sql_data": None,
                "downloads": None,
                "extract": {
                    "status": "status",
                    "msg": "msg",
                    "totalCount": "data.totalCount",
                },
                "checker": {
                    "code": 200,
                    "json": [
                        "status==`0`",
                        "msg==`Success`",
                        "data.totalCount==`1613`",
                        "data.pageSize==`5`",
                    ],
                    "re": None,
                    "contains": [
                        "totalCount",
                        "totalPage"
                    ]
                }
            }
        ]
    }
    host = "http://bitsun-uat.cc0b9108c833e4298b9db565441546718.cn-shanghai.alicontainer.com/"
    username = "admin"
    password = "123456"
    # case_suit = CaseSuiteBase(**test_case)
    # print(case_suit)
    # print(case_suit.suite_name)
    current_session = BitSunLogin(host, username, password).user_login()
    # test_result = TestEngine(case_suit, current_session, host).run()
    # print(json.dumps(json.loads(test_result), indent=4, ensure_ascii=False))
    start(current_session, host, [test_case])
